import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.HashMap;


public class dataProcessing extends Thread{
	
	DatagramPacket receivePacket;
	DatagramSocket clientSocket;
	boolean isDiscard;
	boolean isUpdated = false;
	
	
	public dataProcessing(DatagramSocket clientSocket, DatagramPacket receivePacket){
		this.receivePacket = receivePacket;
		this.clientSocket = clientSocket;
		start();
	}
	
	public void run(){
		
		//unpack the data
		String dataTemp = new String(receivePacket.getData());
		int length = receivePacket.getLength();
		String data = "";
		for(int i=0;i<length;i++)
		{
			data = data + dataTemp.charAt(i);
		}
		String[] msg = data.split("#");
		if(!data.contains("probe")){
			System.out.println("received packet: "+ data);
		}
		
		
		//get sender port
		String[] sender = msg[1].split(";");
		int senderPort = Integer.parseInt(sender[0]);
		double senderDistance = 0;
		
		if(cnnode.receiveMap.containsKey(senderPort) && msg[2].equals("info")){
			senderDistance = Double.parseDouble(sender[1]);
			cnnode.neighborList.put(senderPort, senderDistance);
			System.out.println(cnnode.selfPort+" ditance to "+senderPort+" update to "+senderDistance);
		}
		
		//if this is a ack for probe
		if(msg.length == 3 && msg[2].equals("probe_ack")){
			cnnode.probeCounter.get(Integer.parseInt(msg[1])).receiveProbe++;
		}
		
		else if(msg.length == 3 && msg[2].equals("probe") && cnnode.receiveMap.containsKey(senderPort)){
			double p = Math.random();
			if(p < cnnode.receiveMap.get(senderPort)){
				isDiscard = true;
			}
			else{
				isDiscard = false;
			}
			
			if(!isDiscard){
				sendProbeAck(senderPort, clientSocket);
			}
		}
		
		else if(msg[2].equals("info")){
			
			HashMap<Integer, Double> receivedTable = new HashMap<Integer, Double>();
			
			for(int i = 3; i+1 < msg.length; i=i+2){
				receivedTable.put(Integer.parseInt(msg[i]), Double.parseDouble(msg[i+1]));
				System.out.println(Integer.parseInt(msg[i]) + " "+ Double.parseDouble(msg[i+1]) + "added to receive table for port "+senderPort);
			}
			
			if(cnnode.dv.isEmpty()){
				
				isUpdated = true;
				
				cnnode.dv.put(cnnode.selfPort,new table(cnnode.selfPort, 0.00));
				
				for(Integer i : cnnode.neighborList.keySet()){
					cnnode.dv.put(i, new table(i, cnnode.neighborList.get(i)));
				}
			}
			
			cnnode.neighborDv.put(senderPort, receivedTable);
				
			for(Integer i:receivedTable.keySet()){
					
				if(i == cnnode.selfPort){
					continue;
				}
					
				if(!cnnode.dv.containsKey(i)){
					isUpdated = true;
					cnnode.dv.put(i, new table(senderPort, cnnode.neighborList.get(senderPort)+receivedTable.get(i)));
					System.out.println("adds "+i+" "+senderPort+"=>"+cnnode.neighborList.get(senderPort)+receivedTable.get(i)+"to "+cnnode.selfPort+"dv table");
				}
					
				else if(cnnode.dv.get(i).distance > cnnode.neighborList.get(senderPort)+receivedTable.get(i)){
					
					isUpdated = true;
					double dis =cnnode.neighborList.get(senderPort)+receivedTable.get(i);
					cnnode.dv.put(i, new table(senderPort, dis));
					System.out.println("[update]adds "+i+" "+senderPort+"=>"+dis+"to "+cnnode.selfPort+"dv table");
				
				}
				
				
			}
			cnnode.dispalayRoutingTable();
			
		}
		
		
		
		if(isUpdated){
			
		String table = "";
			
		for(Integer i:cnnode.dv.keySet()){
			table = table + "#" + String.valueOf(i) + "#" + String.valueOf(cnnode.dv.get(i).distance);
		}
		
		table = table.substring(1);
			
		for(Integer i:cnnode.neighborList.keySet()){
			String str = table;
			if(cnnode.probeCounter.containsKey(i)){
				str = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort)+";"+String.valueOf(cnnode.neighborList.get(i)) +"#info#"+str; 
			}
			else{
				str = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort) +"#info#"+str;
			}
			byte[] sendData = str.getBytes();
			try{
				DatagramPacket SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), i);
				clientSocket.send(SendPacket);
				System.out.println(cnnode.currentTime()+"Message sent from Node "+cnnode.selfPort+" to Node "+ i+"["+str+"]");
			}catch (Exception e) {
				e.printStackTrace();
			}
		}}
	}

	

	private static void sendProbeAck(int port, DatagramSocket socket) {
		
		String msg = String.valueOf(System.currentTimeMillis())+ "#" + String.valueOf(cnnode.selfPort) +"#probe_ack"; 
		
		byte[] sendData = msg.getBytes();
		
		try{
			DatagramPacket SendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("localHost"), port);
			socket.send(SendPacket);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}
